/* Declarations for the table type.

   This file is part of khipu.

   khipu is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#ifndef __KP_TABLE__
#define __KP_TABLE__   1

#include "thread.hpp"
#include "initop.hpp"

KP_DECLS_BEGIN

struct table : public varobj
{
  static const int code = typecode::TABLE;

  object vector;
  object cmpfct;
  object hashfct;
  atomic_t lock;
  atomic_t grow_limit;
  float mv_ratio;

  struct iterator
    {
      valref c_key;
      valref c_val;
      valref vec;
      int idx;

      iterator (interpreter *interp, object table);

      iterator (interpreter *interp, const iterator& right) :
          c_key (interp, *right.c_key), c_val (interp, *right.c_val),
          vec (interp, *right.vec), idx (right.idx)
        {
        }

      bool valid () const
        {
          return (this->idx >= 0);
        }

      iterator& operator++ ();
      iterator operator++ (int);

      object key () const
        {
          return (*this->c_key);
        }

      object val () const
        {
          return (*this->c_val);
        }
    };

  size_t capacity () const;
};

inline table* as_table (object obj)
{
  return ((table *)unmask (obj));
}

inline bool table_p (object obj)
{
  return (itype (obj) == typecode::TABLE);
}

/* Allocate a table that uses EQFN for key lookups and HASHFN
 * to compute hash codes. NIL may be used for both, in which
 * case, an appropiate default will be used. */
KP_EXPORT result<object> alloc_table (interpreter *interp,
                                      object eqfn, object hashfn);

/* Get the value associated to key KEY in table TAB. If not found,
 * return DFL. MTSAFE specifies whether we should use a multi-thread
 * safe routine or not. */
KP_EXPORT result<object> table_get (interpreter *interp, object tab,
                                    object key, object dfl, bool mtsafe);

/* Associate value VAL to key KEY in table TAB. MTSAFE is used in
 * the same manner as with 'table_get'. Returns true if the key was
 * not present, false otherwise. */
KP_EXPORT result<bool> table_put (interpreter *interp, object tab,
                                  object key, object val, bool mtsafe);

/* Remove the entry with KEY in table TAB and return the value that was
 * associated to it, or DFL, if they key was not present. MTSAFE is used in
 * the same manner as with the rest of the API. */
KP_EXPORT result<object> table_pop (interpreter *interp, object tab,
                                    object key, object dfl, bool mtsafe);

/* Clear the table TAB. MTSAFE is used in the same manner as
 * with 'table_get'. */
KP_EXPORT result<void> table_clr (interpreter *interp,
                                  object tab, bool mtsafe);

/* Shortcuts for the above, where the MTSAFE parameter is deduced
 * from the number of running threads. */

KP_EXPORT result<object> nput_u (interpreter *interp,
                                 object tab, object key, object val);

KP_EXPORT result<object> get_u (interpreter *interp,
                                object tab, object key, object dfl);

KP_EXPORT result<object> npop_u (interpreter *interp,
                                 object tab, object key, object dfl);

inline result<int> table_clr (interpreter *interp, object tab)
{
  return (table_clr (interp, tab, !singlethr_p ()));
}

// Mutate the value associated to a key inside a table.
KP_EXPORT result<object> nzap_u (interpreter *interp, object obj, object key,
                                 uint32_t flags, object fn,
                                 object *argv, int argc);

// Fetch the number of items in table TAB.
KP_EXPORT uint32_t len_u (object tab);

// Return the hashcode for the table TAB.
KP_EXPORT result<uint32_t> hash_u (interpreter *interp, object tab);

// Copy a table.
KP_EXPORT result<object> copy_u (interpreter *interp, object obj, bool deep);

KP_EXPORT result<object> iter_u (interpreter *interp,
                                 object obj, object token, bool adv);

// Write a table to a stream.
KP_EXPORT result<int64_t> write_u (interpreter *interp,
                                   stream *strm, object obj, io_info& info);

// Serialize a table to a stream.
KP_EXPORT result<int64_t> pack_u (interpreter *interp,
                                  stream *strm, object obj, pack_info& info);

// Deserialize a table from a stream.
KP_EXPORT result<object> unpack_u (interpreter *interp,
                                   stream *strm, pack_info& info, bool save);

// Init OP for tables.
KP_EXPORT init_op init_tables;

KP_DECLS_END

#endif

